package metric.gui.swt.explorer;

import java.util.Observable;
import java.util.Observer;

import metric.core.MetricEngine;
import metric.core.persistence.CSVConverter;
import metric.core.persistence.MetricDataConverter;
import metric.core.persistence.XMLConverter;
import metric.core.vocabulary.SupportedFileType;
import metric.gui.swt.core.dialog.OpenDialog;
import metric.gui.swt.core.dialog.ProgressDialog;
import metric.gui.swt.core.threading.ThreadedMetricDataConverter;
import metric.gui.swt.core.threading.ThreadedMetricEngine;
import metric.gui.swt.core.util.SWTUtils;
import metric.gui.swt.core.vocabulary.GUI;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

/**
 * Represents the top composite in this GUI. This includes the directory text
 * field and associated browse/update buttons.
 * 
 * Acts as an <code>Observer</code> to the <code>MetricEngine</code> and
 * <code>MetricConverter</code> in order to display progress information.
 * 
 * Is responsible for handling any listener events generated by components in
 * this class.
 * 
 * @author Joshua Hayes,Swinburne University (ICT),2007
 */
public class TopComposite extends Composite implements SelectionListener,
		Observer
{
	private static final String[] MODEL_FILTER_EXTENSIONS = { SupportedFileType.VERSION.getExtension(),
		SupportedFileType.CSV.getExtension(), SupportedFileType.XML.getExtension() };
	private static final String[] MODEL_FILTER_EXT_NAMES = { SupportedFileType.VERSION.getExtensionName(),
		SupportedFileType.CSV.getExtensionName(), SupportedFileType.XML.getExtensionName()};

	private Text tDirField;
	private Button bDirBrowse, bDirUpdate;
	private Shell shell;
	private JSeatExplorer parent;
	private List lVersions;
	private ProgressDialog pDialog;
	private ThreadedMetricDataConverter tc;
	private ThreadedMetricEngine tme;

	public TopComposite(JSeatExplorer parent, Shell shell, int type)
	{
		super(shell, type);
		this.shell = shell;
		this.parent = parent;

		GridData topGridData = new GridData(GridData.FILL_HORIZONTAL);
		topGridData.horizontalSpan = 2;
		setLayout(new GridLayout());
		setLayoutData(topGridData);

		// Directory
		GridData topGroupGridData = new GridData(GridData.FILL_HORIZONTAL);
		GridLayout topGridLayout = new GridLayout(4, false);
		Group topGroup = SWTUtils.createGroup(this, SWT.NONE, "Model Data",
				topGridLayout, topGroupGridData);

		SWTUtils.createLabel(topGroup, SWT.NONE, "Directory");

		// Textfield
		tDirField = SWTUtils.createText(topGroup, SWT.BORDER, new GridData(
				GridData.FILL_HORIZONTAL));

		bDirBrowse = SWTUtils.createButton(topGroup, SWT.PUSH, "Browse",
				this);
		bDirUpdate = SWTUtils.createButton(topGroup, SWT.PUSH, "Update",
				this);

		this.pack();
	}

	public void widgetDefaultSelected(SelectionEvent arg0)
	{
	} // Not interested in this.

	public void widgetSelected(SelectionEvent event)
	{
		// Open version data.
		if (event.getSource() == bDirBrowse)
		{
			String filterPath = parent.getProperty(GUI.DEFAULT_VERSION_DIR);
			OpenDialog od = new OpenDialog(shell, MODEL_FILTER_EXTENSIONS,
					MODEL_FILTER_EXT_NAMES, filterPath);
			String selected = od.open();

			// Update directory box with selected path.=
			if (selected != null)
			{
				tDirField.setText(selected);
				if (Boolean.parseBoolean(parent.getProperty(GUI.AUTO_PROCESS)))
				{
					processHistoryFromFile(selected);
				}
			}
		} // end dirBrowseButton event.
		else if (event.getSource() == bDirUpdate)
		{
			processHistoryFromFile(tDirField.getText());
		} else if (event.getSource() == pDialog.getCancelButton())
		{
			tme.interrupt();
			pDialog.dispose();
		}
	}

	public void update(Observable observable, Object arg1)
	{
		if (observable instanceof MetricDataConverter)
		{
			MetricDataConverter mc = (MetricDataConverter) observable;
			int value = mc.getCompletion();
			pDialog.updateForMe(value);

//			if (value == 100)
//			{
//				Runnable toRun = new Runnable()
//				{
//					public void run()
//					{
//						// Wait for threaded converter to finish converting.
//						HistoryMetricData hmd = (HistoryMetricData) tc.get();
//						Collection<VersionMetricData> c = hmd.getVersionList();
//
//						lVersions.removeAll();
//						lVersions.setData(hmd);
//						for (VersionMetricData vmd : c)
//						{
//							lVersions.add(vmd.toString());
//						}
//					}
//				};
//				Display.getDefault().asyncExec(toRun);
//			}
		} else if (observable instanceof MetricEngine)
		{
			MetricEngine me = (MetricEngine) observable;
			int value = me.getCompletion();
			pDialog.updateForMe(value);
		}
	}

	public void setVersions(List versions)
	{
		this.lVersions = versions;
	}

	/**
     * Opens a new <code>ProgressDialog</code>
     * 
     * @param title The title of the ProgressDialog.
     */
	private void openNewProgressDialog(String title)
	{
		pDialog = new ProgressDialog(title, "Please wait...", 100);
		pDialog.getCancelButton().addSelectionListener(this);
		SWTUtils.centerDialog(shell, pDialog.getShell());
		pDialog.open();
	}

	/**
     * Starts the <code>ThreadedConverter</code> to process the specified file
     * if it is not a general versions file. Opens a <code>ProgressDialog</code>
     * to display update information from the <code>MetricEngine</code>.
     * 
     * @param filename The file to process.
     */
	private void processHistoryFromFile(String filename)
	{
		MetricDataConverter mc = null;
		if (filename.indexOf(".ver") != -1)
		{
			processHistoryFromVersionsFile(filename);
			return;
		} else if (filename.indexOf(".mmd") != -1) // Must be
		// csv model data.
		{
			mc = new CSVConverter();
			mc.addObserver(this);
		} else if (filename.indexOf(".xmd") != -1)
		{
			mc = new XMLConverter();
			mc.addObserver(this);
		}

		try
		{
			tc = new ThreadedMetricDataConverter(mc, filename, lVersions, this);
			openNewProgressDialog("Restoring model data...");
			tc.start();
		} catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	/**
     * Starts the <code>ThreadedMetricEngine</code> to process the specified
     * filename. Opens a <code>ProgressDialog</code> to display update
     * information from the <code>MetricEngine</code>.
     * 
     * @param filename The file the ThreadedMetricEngine should process.
     */
	private void processHistoryFromVersionsFile(String filename)
	{
		tme = new ThreadedMetricEngine(this, lVersions, filename);
		tme.start();

		// Show new progress dialog.
		openNewProgressDialog("Processing version(s)");
	}
}
